﻿using DBUtil.FastEntity.Annotations;
using DotNetCommon.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;
using System.Text;

namespace DBUtil.FastEntity
{
    public class EntityInfo
    {
        public string TableName { get; set; }
        public string SchemaName { get; set; }
        public string FullName { get; set; }
        public Type Type { get; set; }
        public string TypeFullName { get; set; }

        //tree
        public bool IsTree { get; set; }
        public EnumTableTreeType? TreeType { get; set; }

        //audit
        public bool IsAudit => EntityPropertyInfos.Any(i => i.IsAudit);

        public List<EntityPropertyInfo> EntityPropertyInfos { get; set; } = new List<EntityPropertyInfo>();

        public EntityInfo Clone()
        {
            var entityInfo = new EntityInfo()
            {
                TableName = this.TableName,
                SchemaName = this.SchemaName,
                FullName = this.FullName,
                IsTree = this.IsTree,
                Type = this.Type,
                TypeFullName = this.TypeFullName,
                TreeType = this.TreeType,
                EntityPropertyInfos = this.EntityPropertyInfos.Select(i => new EntityPropertyInfo()
                {
                    ColumnName = i.ColumnName,
                    DefaultValue = i.DefaultValue,
                    IsColumn = i.IsColumn,
                    IsIgnoreInsert = i.IsIgnoreInsert,
                    IsIgnoreSelect = i.IsIgnoreSelect,
                    IsIgnoreUpdate = i.IsIgnoreUpdate,
                    IsIgnoreWrite = i.IsIgnoreWrite,
                    IsPrimaryKey = i.IsPrimaryKey,
                    IsRawString = i.IsRawString,
                    IsReferColumn = i.IsReferColumn,
                    IsReferTable = i.IsReferTable,
                    IsTableTreeChildren = i.IsTableTreeChildren,
                    IsTableTreeId = i.IsTableTreeId,
                    IsTableTreeParentId = i.IsTableTreeParentId,
                    IsUseReferHitTable = i.IsUseReferHitTable,
                    Order = i.Order,
                    PrimaryKeyArg = i.PrimaryKeyArg,
                    PrimaryKeyStrategy = i.PrimaryKeyStrategy,
                    EntityIdGenerator = i.EntityIdGenerator,
                    PropertyInfo = i.PropertyInfo,
                    PropertyType = i.PropertyType,
                    PropName = i.PropName,
                    ReferColumn_ReferHint = i.ReferColumn_ReferHint,
                    ReferColumn_ReferProp = i.ReferColumn_ReferProp,
                    ReferHits = i.ReferHits.Select(i => new EntityReferHitInto
                    {
                        ReferHitType = i.ReferHitType,
                        ReferName = i.ReferName,
                        ReferProp = i.ReferProp,
                        ReferTable = i.ReferTable,
                        SplitString = i.SplitString,
                        StaticReferProp1 = i.StaticReferProp1,
                        StaticReferProp2 = i.StaticReferProp2,
                        StaticReferProp3 = i.StaticReferProp3,
                        StaticReferValue1 = i.StaticReferValue1,
                        StaticReferValue2 = i.StaticReferValue2,
                        StaticReferValue3 = i.StaticReferValue3,
                        StaticThisValue = i.StaticThisValue
                    }).ToList(),
                    ReferTable_ReferHint = i.ReferTable_ReferHint,
                    TableTreeIdSegment = i.TableTreeIdSegment,
                    TypeName = i.TypeName,
                    TypeNum = i.TypeNum,
                    UseReferHitTable_UseReferHitTable = i.UseReferHitTable_UseReferHitTable,
                    AuditDefaultValue = i.AuditDefaultValue,
                    IsAuditInitUseCreateValue = i.IsAuditInitUseCreateValue,
                    IsAuditCreateTime = i.IsAuditCreateTime,
                    IsAuditCreateUserId = i.IsAuditCreateUserId,
                    IsAuditUpdateTime = i.IsAuditUpdateTime,
                    IsAuditUpdateUserId = i.IsAuditUpdateUserId,
                    IsAuditDeleteTime = i.IsAuditDeleteTime,
                    IsAuditDeleteUserId = i.IsAuditDeleteUserId,

                    //
                    IsStoreJson = i.IsStoreJson,
                    IsStoreJsonFast = i.IsStoreJsonFast,
                    StoreJsonFastAllNumDigit = i.StoreJsonFastAllNumDigit,
                    StoreJsonFastDateFormatString = i.StoreJsonFastDateFormatString,
                    StoreJsonFastDecimalDigit = i.StoreJsonFastDecimalDigit,
                    StoreJsonFastEnum2String = i.StoreJsonFastEnum2String,
                    StoreJsonFastIgnoreNull = i.StoreJsonFastIgnoreNull,
                    StoreJsonFastIsAllToString = i.StoreJsonFastIsAllToString,
                    StoreJsonFastIsIntend = i.StoreJsonFastIsIntend,
                    StoreJsonFastIsLongToString = i.StoreJsonFastIsLongToString,
                    StoreJsonFastLowerCamelCase = i.StoreJsonFastLowerCamelCase,
                }).ToList()
            };
            return entityInfo;
        }

        #region PK、Audit、Normal列
        public EntityPropertyInfo PrimaryKeyColumn => EntityPropertyInfos.FirstOrDefault(i => i.IsPrimaryKey);
        public List<EntityPropertyInfo> AuditColumns => EntityPropertyInfos.Where(i => i.IsAudit && !i.IsPrimaryKey).ToList();
        public List<EntityPropertyInfo> NormalColumns => EntityPropertyInfos.Where(i => !i.IsAudit && !i.IsPrimaryKey).ToList();
        public EntityInfo DisableAuditAttribute(params string[] props)
        {
            if (props.IsNotNullOrEmpty())
            {
                foreach (var prop in props)
                {
                    foreach (var col in AuditColumns)
                    {
                        if (prop == col.PropName)
                            col.IsAuditCreateTime
                                = col.IsAuditCreateUserId
                                = col.IsAuditUpdateTime
                                = col.IsAuditUpdateUserId
                                = col.IsAuditDeleteTime
                                = col.IsAuditDeleteUserId = false;
                    }
                }
            }
            return this;
        }
        public EntityInfo DisableAllAuditAttribute(params string[] props)
        {
            if (props.IsNotNullOrEmpty())
            {
                foreach (var col in AuditColumns)
                {
                    col.IsAuditCreateTime
                        = col.IsAuditCreateUserId
                        = col.IsAuditUpdateTime
                        = col.IsAuditUpdateUserId
                        = col.IsAuditDeleteTime
                        = col.IsAuditDeleteUserId = false;
                }
            }
            return this;
        }
        public EntityInfo RemoveAuditColumns(params string[] props)
        {
            if (props.IsNotNullOrEmpty())
            {
                for (int i = EntityPropertyInfos.Count - 1; i >= 0; i--)
                {
                    var col = EntityPropertyInfos[i];
                    if (!col.IsAudit) continue;
                    if (props.Contains(col.PropName)) EntityPropertyInfos.RemoveAt(i);
                }
            }
            return this;
        }
        public EntityInfo RemoveAllAuditColumnsExcept(params string[] props)
        {
            if (props.IsNotNullOrEmpty())
            {
                for (int i = EntityPropertyInfos.Count - 1; i >= 0; i--)
                {
                    var col = EntityPropertyInfos[i];
                    if (!col.IsAudit) continue;
                    if (!props.Contains(col.PropName)) EntityPropertyInfos.RemoveAt(i);
                }
            }
            return this;
        }
        public EntityInfo RemoveNormalColumns(params string[] props)
        {
            if (props.IsNotNullOrEmpty())
            {
                for (int i = EntityPropertyInfos.Count - 1; i >= 0; i--)
                {
                    var col = EntityPropertyInfos[i];
                    if (col.IsPrimaryKey || col.IsAudit) continue;
                    if (props.Contains(col.PropName)) EntityPropertyInfos.RemoveAt(i);
                }
            }
            return this;
        }
        public EntityInfo RemoveAllNormalColumnsExcept(params string[] props)
        {
            if (props.IsNotNullOrEmpty())
            {
                for (int i = EntityPropertyInfos.Count - 1; i >= 0; i--)
                {
                    var col = EntityPropertyInfos[i];
                    if (col.IsPrimaryKey || col.IsAudit) continue;
                    if (!props.Contains(col.PropName)) EntityPropertyInfos.RemoveAt(i);
                }
            }
            return this;
        }
        #endregion

        /// <summary>
        /// 是否是有效的主键值
        /// </summary>
        /// <param name="primaryValue"></param>
        /// <returns></returns>
        public bool IsValidPrimaryValue(object primaryValue)
        {
            return primaryValue != null && primaryValue?.ToString() != PrimaryKeyColumn.DefaultValue?.ToString();
        }
    }

    public class EntityPropertyInfo
    {
        public PropertyInfo PropertyInfo { get; set; }
        public Type PropertyType { get; set; }
        public object DefaultValue { set; get; }
        /// <summary>
        /// 属性名称
        /// </summary>
        public string PropName { get; set; }
        public int? TypeNum { get; set; }
        public bool IsColumn { get; set; }

        public string ColumnName { get; set; }
        public string TypeName { get; set; }
        public int Order { get; set; }


        /*ignore notmapped*/
        public bool IsIgnoreUpdate { get; set; }
        public bool IsIgnoreSelect { get; set; }
        public bool IsIgnoreInsert { get; set; }
        public bool IsIgnoreWrite { get; set; }

        //纯sql模式
        public bool IsRawString { get; set; }

        //audit
        public bool IsAuditCreateTime { get; set; }
        public bool IsAuditInitUseCreateValue { get; set; }
        public bool IsAuditCreateUserId { get; set; }
        public bool IsAuditUpdateTime { get; set; }
        public bool IsAuditUpdateUserId { get; set; }
        public bool IsAuditDeleteTime { get; set; }
        public bool IsAuditDeleteUserId { get; set; }
        public object AuditDefaultValue { get; set; }

        public bool IsAudit => IsAuditCreateTime || IsAuditCreateUserId || IsAuditUpdateTime || IsAuditUpdateUserId || IsAuditDeleteTime || IsAuditDeleteUserId;

        /*主键*/
        public bool IsPrimaryKey { get; set; }
        public KeyStrategy? PrimaryKeyStrategy { get; set; }
        public object PrimaryKeyArg { get; set; }
        public IEntityIdGenerator EntityIdGenerator { get; set; }

        /*树相关*/
        public bool IsTableTreeId { get; set; }
        public bool IsTableTreeParentId { get; set; }
        public bool IsTableTreeChildren { get; set; }
        public string TableTreeIdSegment { get; set; }


        /*ReferHit 可多个*/
        public List<EntityReferHitInto> ReferHits { get; set; } = new List<EntityReferHitInto>();
        public bool IsReferHit => ReferHits.IsNotNullOrEmpty();

        /*UseReferHitTable*/
        public bool IsUseReferHitTable { get; set; }
        public Type UseReferHitTable_UseReferHitTable { get; set; }
        //public EntityInfo UseReferHitTable_UseReferHitTableEntityInfo { get; set; }

        /*ReferColumn*/
        public bool IsReferColumn { get; set; }
        public string ReferColumn_ReferHint { get; set; }
        public string ReferColumn_ReferProp { get; set; }
        //public EntityPropertyInfo ReferColumn_ReferPropEntityPropertyInfo { get; set; }

        /*ReferTable*/
        public bool IsReferTable { get; set; }
        public string ReferTable_ReferHint { get; set; }
        //public EntityPropertyInfo ReferTable_ReferHintEntityPropertyInfo { get; set; }

        /*storejson*/
        public bool IsStoreJson { get; set; }
        public bool IsStoreJsonFast { get; set; }

        public string StoreJsonFastDateFormatString { get; set; }
        public bool StoreJsonFastIsLongToString { get; set; }
        public bool StoreJsonFastIgnoreNull { get; set; }
        public bool StoreJsonFastEnum2String { get; set; }
        public bool StoreJsonFastLowerCamelCase { get; set; }
        public bool StoreJsonFastIsIntend { get; set; }
        public bool StoreJsonFastIsAllToString { get; set; }
        public int? StoreJsonFastAllNumDigit { get; set; }
        public int? StoreJsonFastDecimalDigit { get; set; }

    }

    public class EntityReferHitInto
    {
        public string ReferName { get; set; }

        public EnumReferHitType ReferHitType { get; set; }
        public string SplitString { get; set; }

        public Type ReferTable { get; set; }
        //public EntityInfo ReferEntityInfo { get; set; }

        public string ReferProp { get; set; }
        //public EntityPropertyInfo ReferPropEntityPropertyInfo { get; set; }

        public object StaticThisValue { get; set; }

        public string StaticReferProp1 { get; set; }
        //public EntityPropertyInfo StaticReferProp1PropertyInfo { get; set; }
        public object StaticReferValue1 { get; set; }

        public string StaticReferProp2 { get; set; }
        //public EntityPropertyInfo StaticReferProp2PropertyInfo { get; set; }
        public object StaticReferValue2 { get; set; }

        public string StaticReferProp3 { get; set; }
        //public EntityPropertyInfo StaticReferProp3PropertyInfo { get; set; }
        public object StaticReferValue3 { get; set; }
    }
}
